
#include <math.h>
#include "SparseMatrix.h"
#include "LsqrTypes.h"



void SparseMatrix::SetLogTextStream(QTextStream *p)
{
    logTextStream = p;
}

void SparseMatrix::matVecMult( long  mode, dvec  *x, dvec  *y){
  //  prod_data *prod
//  test_mult (mode, x, y, prod);
    /*
    *     Compute  Y = Y + A*X
    */
    //debug begin
//    QTime t;
//    t.start();
    //debug end

    int cols = x->length;
    int rows = y->length;


    if(CRS_CCS)
    {
        int beginIndex = 0;
        int endIndex = 0;

        if( mode == 0 )
        {
            for(int i=0; i<rows; i++)
            {
                beginIndex = row_ptr[i];
                endIndex = row_ptr[i+1];

                float res = 0.0f;
                for(int j=beginIndex; j<endIndex; j++)
                {
                    int tmpCol = col_ind[j];
                    float value = pDataRow[j];
                    res += value*x->elements[tmpCol];
                }
                y->elements[i] += res;
            }
        }
        /*
         *     Compute  X = X + A^T*Y
         */
        if( mode == 1 )
        {
            for(int i=0; i<cols; i++)
            {
                beginIndex = col_ptr[i];
                endIndex = col_ptr[i+1];

                float res = 0.0f;
                for(int j=beginIndex; j<endIndex; j++)
                {
                    int tmpRow = row_ind[j];
                    float value = pDataCol[j];
                    res += value*y->elements[tmpRow];
                }
                x->elements[i] += res;
            }
        }


    }
    else
    {

         if( mode == 0 )
         {
             for(int i=0; i<rows; i++)
             {
                 std::vector<int> colList = row_col_index[i];
                 int size = colList.size();
                 float res = 0.0f;
                 for(int j=0; j<size; j++)
                 {
                     int tmpCol = colList[j];
                     float value = this->GetElement(i, tmpCol);
                     res += value*x->elements[tmpCol];
                 }
                 y->elements[i] += res;
             }
         }
         /*
          *     Compute  X = X + A^T*Y
          */
         if( mode == 1 )
         {
             for(int i=0; i<cols; i++)
             {
                 std::vector<int> rowList = col_row_index[i];
                 int size = rowList.size();
                 float res = 0.0f;
                 for(int j=0; j<size; j++)
                 {
                     int tmpRow = rowList[j];
                     float value = this->GetElement(tmpRow, i);
                     res += value*y->elements[tmpRow];
                 }
                 x->elements[i] += res;
             }
         }

    }

    //debug begin
/*  QString str = QString("%1\n").arg(t.elapsed());
  if(logTextStream)
  {
       *logTextStream<<str;
      logTextStream->flush();
  }*/
  //debug end

}

void SparseMatrix::SetElement(int row, int col, float value)
{
    std::vector<int>& cols = row_col_index[row];
    cols.push_back(col);

    std::vector<int>& rows = col_row_index[col];
    rows.push_back(row);

    int index = row * ncol + col;
    data.insert(std::pair<int, float>(index, value));
}

float SparseMatrix::GetElement(int row, int col)
{
    float value =0.0f;
    int index = row * ncol + col;

    if(data.find(index) != data.end())
        value  = data[index];
    else
        value = 0.0f;

    return value;
}

void SparseMatrix::RowCopy(int rowCpyFrom, int rowCpyTo)
{
    std::vector<int> colList = row_col_index[rowCpyFrom];
    int size = colList.size();
    for(int j=0; j<size; j++)
    {
       int tmpCol = colList[j];
       float value = this->GetElement(rowCpyFrom, tmpCol);
       this->SetElement(rowCpyTo, tmpCol, value);
    }
}

void SparseMatrix::ColCopy(int colCpyFrom, int ColCpyTo)
{
    std::vector<int> rowList = col_row_index[colCpyFrom];
    int size = rowList.size();
    for(int j=0; j<size; j++)
    {
        int tmpRow = rowList[j];
        float value = this->GetElement(tmpRow, colCpyFrom);
        this->SetElement(tmpRow, ColCpyTo, value);
    }
}

void SparseMatrix::OutputMatrix(std::string fileName)
{
    std::ofstream ofile(fileName);
    ofile<<"m=[\n";
    for(int i=0; i<nrow; i++)
    {
        std::vector<int> colList = row_col_index[i];
        int size = colList.size();
        for(int j=0; j<size; j++)
        {
           int tmpCol = colList[j];
           float value = this->GetElement(i, tmpCol);
           ofile<<i<<"\t"<<tmpCol<<"\t"<<value<<std::endl;
        }
    }
    ofile<<"];";
    ofile.close();
}

void SparseMatrix::TransferToCRS_CCSStroage()
{
    numElts = data.size();

    //Compressed Row Storage (CRS)
    pDataRow = new float[numElts];
    col_ind = new int[numElts];
    row_ptr = new int[nrow+1];
    int k=0;
    for(int i=0; i<nrow; i++)
    {
        std::vector<int> colList = row_col_index[i];
        int size = colList.size();
        if(size)
        {
            row_ptr[i] = k;
            for(int j=0; j<size; j++)
            {
                int tmpCol = colList[j];
                float value = this->GetElement(i, tmpCol);
                pDataRow[k] = value;
                col_ind[k] = tmpCol;
                k++;
            }
        }
        else
        {
            row_ptr[i] = -1;
        }
    }
    row_ptr[nrow] = numElts;



    //Compressed Column Storage (CCS)
    pDataCol = new float[numElts];
    row_ind = new int[numElts];
    col_ptr = new int[ncol+1];
    k=0;
    for(int i=0; i<ncol; i++)
    {
        std::vector<int> rowList = col_row_index[i];
        int size = rowList.size();
        if(size)
        {
            col_ptr[i] = k;
            for(int j=0; j<size; j++)
            {
                int tmpRow = rowList[j];
                float value = this->GetElement(tmpRow, i);
                pDataCol[k] = value;
                row_ind[k] = tmpRow;
                k++;
            }
        }
        else
        {
            col_ptr[i] = -1;
        }
    }
    col_ptr[ncol] = numElts;
    CRS_CCS = true;


}
